import http.client
import base64
import json
import time
from bottle import route, view, response
from mamba.utils import Item, format_time, format_duration
import mamba.config as config
from mamba.video import osditems


""" an interface to tvheadend """

__author__ = "Johannes Koester"

_tvheadend_server = config.config().get("tvheadend", "server", fallback="localhost:9981")
_username = config.config().get("tvheadend", "user", fallback="frontend")
_password = config.config().get("tvheadend", "password", fallback="0000")

_headers = {"Authorization": "Basic {}".format(base64.encodestring("{}:{}".format(_username, _password).encode())[:-1].decode())}

def tvheadend(url):
	_tvheadend = http.client.HTTPConnection(_tvheadend_server)
	_tvheadend.request("GET", url, headers=_headers)
	resp = _tvheadend.getresponse().read()
	_tvheadend.close()
	return json.loads(resp.decode())

def fetch_channels():
	return tvheadend("/channels?op=list")

def _fetch_epg():
	return tvheadend("/epg?limit=1000")


@route("/tv")
@view("list")
def tv():
	return dict(goback = True,
	            items = [Item(id="EPG", action="tv/running"),
	                     Item(id="Timer", action="tv/timer")])

def timer():
	t = tvheadend("/dvrlist")
	items = []
	print(t)
	for entry in t["entries"]:
		start = entry["start"]
		duration = entry["duration"]
		running = start < time.time() < start + duration
		yield entry, running

def next_timer_start():
	nextstart = None
	for entry, running in timer():
		if entry["end"] < time.time():
			continue
		if nextstart is None or nextstart > entry["start"]:
			nextstart = entry["start"]
	return nextstart

@route("/tv/timer")
@view("list")
def _timer():
	items = []
	for entry, running in timer():
		items.append(
		             Item(id=entry["id"],
		                  text=[entry["title"], format_time(entry["start"]), format_duration(entry["duration"]), entry["status"], entry["channel"]],
		                  action="timer/{}".format(entry["id"],
		                  highlight=True)

		             )
		)
	return dict(goback = True, items = items)


@route("/tv/epg/<channelid:int>")
@view("list")
def epg(channelid):
	epg = _fetch_epg()
	items = []
	for entry in epg["entries"]:
		if entry["channelid"] == channelid:
			items.append(epg_item(entry, "tv/epgdetail/{}".format(entry["id"])))
	return dict(goback = True, items = items)

def epg_item(entry, action):
	start = entry["start"]
	duration = entry["duration"]
	running = start < time.time() < start + duration
	schedstate = entry.get("schedstate", "")
	return Item(id=entry["id"], 
		        text=[entry["title"], schedstate, entry["channel"]],
		        highlight=running,
		        action=action)

def is_running(entry):
	return entry["start"] < time.time() < entry["start"] + entry["duration"]


@route("/tv/running")
@view("list")
def running():
	channels = fetch_channels()
	epg = dict((entry["channelid"], entry) for entry in tvheadend("/epg?limit={}".format(len(channels["entries"])))["entries"] if is_running(entry))
	items = []
	for entry in sorted(channels["entries"], key=lambda e: e["chid"]):
		channelid = entry["chid"]
		channelname = entry["name"]
		if channelid in epg:
			items.append(epg_item(epg[channelid], "tv/channeldetail/{}/{}".format(channelid, channelname)))
		else:
			items.append(Item(id=channelid, 
			                  text=["no epg", channelname], 
			                  action="tv/watch/{}/{}".format(channelid, channelname)))
	return dict(goback = True, items = items)

@route("/tv/epgdetail/<id:int>")
@view("list")
def epg_detail(id):
	epg = _fetch_epg()
	for entry in epg["entries"]:
		if entry["id"] == id:
			items = []
			if is_running(entry):
				items.append(Item(id = "watch", action = "tv/watch/{}".format(entry["channelid"])))
			items.append(Item(id = "record", action = "record/{}".format(id)))
			return dict(goback = True, items = items)
	return dict(goback = True, items = [])

@route("/tv/channeldetail/<channelid:int>/<channel>")
@view("list")
def channel_detail(channelid, channel):
	items = []
	items.append(Item(id = "watch", action = "tv/watch/{}".format(channelid)))
	items.append(Item(id = "EPG", action = "tv/epg/{}".format(channelid)))
	return dict(goback = True, items = items)

@route("/tv/record/<id>")
def record(id):
	tvheadend("/dvr?eventId={}&op=recordEvent".format(id))

@route("/tv/abort_recording/<id>")
def cancel_record(id):
	tvheadend("/dvr?entryId={}&op=cancelEntry".format(id))

@route("/tv/delete_recording/<id>")
def cancel_record(id):
	tvheadend("/dvr?entryId={}&op=deleteEntry".format(id))

@route("/tv/watch/<channelid:int>")
@view("tvplayer")
def watch(channelid):
	channels = fetch_channels()
	for entry in channels["entries"]:
		if entry["chid"] == channelid:
			channelname = entry["name"]
			break
	return dict(src = "tv/stream/{}".format(channelid), channelid = channelid, osd="tv/osd/{}".format(channelid))

@route("/tv/osd/<channelid:int>")
@view("list")
def osd(channelid):
	epg = _fetch_epg()
	items = osditems()
	for entry in epg["entries"]:
		if entry["channelid"] == channelid:
			items.append(epg_item(entry, "tv/epgdetail/{}".format(entry["id"])))
	return dict(goback = True, items = items)

@route("/tv/stream/<channelid>")
def stream_channel(channelid):
	_tvheadend = http.client.HTTPConnection(_tvheadend_server)
	_tvheadend.request("GET", "/stream/channelid/{}".format(channelid), headers=_headers)
	resp = _tvheadend.getresponse()
	response.content_type = "video/x-matroska"
	return resp

def search():
	pass
